#pragma execution_character_set("utf-8")
#include <QUdpSocket>
#include <iostream>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QNetworkInterface>
#include <QDebug>
#include <QTimer>
#include "systimer.h"
#include "udpsys.h"
#include "reporter.h"
#include "devicesetup.h"

void Systimer::processUdpData(QUdpSocket *udpSocket)
{
    QHostAddress hostAddress;
    quint16 hostPort;

    while(udpSocket->hasPendingDatagrams()){
        QByteArray datagram;
        datagram.resize(static_cast<int>(udpSocket->pendingDatagramSize()));

        udpSocket->readDatagram(datagram.data(), datagram.size(), &hostAddress, &hostPort);
        processRecvData(datagram, hostAddress);
    }
}

void Systimer::processTcpData(QTcpSocket *tcpSocket)
{
    QByteArray datagram = tcpSocket->readAll();
    QHostAddress hostAddress = tcpSocket->peerAddress();

    qDebug() << QString("tcp[%1] recv data len: %2").arg(UdpSys::getHostIP(hostAddress)).arg(datagram.size());

    processRecvData(datagram, hostAddress);
}

void Systimer::processRecvData(QByteArray &datagram, QHostAddress &hostAddress)
{
    QString hostIPStr;
    int devIndex =0;

    hostIPStr = UdpSys::getHostIP(hostAddress);
    if(hostIPStr.startsWith(localIP) || hostIPStr.contains("127.0.0.1")){
        //appendLog(QString("recv form: %1").arg(hostIPStr), LOG_DEBUG);
        return;
    }else{
        devIndex  = getIndexFromUListIP(udpDeviceList, hostIPStr);

        // 检查包是否完整
        if(datagram.length() == 0){
            appendLog(QString("[%1]收到的包长度为0???, datalen: %2").arg(hostIPStr).arg(datagram.length()), LOG_WARN);
            return;
        }


        int type = (quint8)datagram.at(0);
        if(type >= CMD_STATUS && type <= CMD_KILLALL){
            if( !UdpSys::isCompletePack(datagram) ){
                appendLog(QString("[%1]检测到不完整包,有帧头,datalen: %2").arg(hostIPStr).arg(datagram.length()), LOG_WARN);
                if(devIndex >= 0){
                    udpDeviceList[devIndex].leftPack.append(datagram);
                    if(UdpSys::isCompletePack(udpDeviceList[devIndex].leftPack)){
                        QByteArray newdatagram = udpDeviceList[devIndex].leftPack;
                        udpDeviceList[devIndex].leftPack.clear();
                        processRecvData(newdatagram, hostAddress);
                    }
                }else{
                    appendLog(QString("[%1]未知IP-检测到不完整包,有帧头,无法进行拼接！！！,datalen: %2").arg(hostIPStr).arg(datagram.length()), LOG_ERR);
                }
                return;
            }
        }else{
            if(devIndex >= 0){
                if(udpDeviceList.at(devIndex).leftPack.length() > 0){
                    appendLog(QString("[%1]检测到不完整包,无帧头,进行拼接,datalen: %2").arg(hostIPStr).arg(datagram.length()), LOG_WARN);
                    udpDeviceList[devIndex].leftPack.append(datagram);
                    if(UdpSys::isCompletePack(udpDeviceList[devIndex].leftPack)){
                        QByteArray newdatagram = udpDeviceList[devIndex].leftPack;
                        udpDeviceList[devIndex].leftPack.clear();
                        processRecvData(newdatagram, hostAddress);
                    }
                }else{
                    //
                    appendLog(QString("[%1]检测到不完整包,无帧头,无法进行拼接！！！,datalen: %2").arg(hostIPStr).arg(datagram.length()), LOG_ERR);
                }
            }else{
                appendLog(QString("[%1]未知IP-检测到不完整包,无帧头,无法进行拼接！！！,datalen: %2").arg(hostIPStr).arg(datagram.length()), LOG_ERR);
            }
            return;
        }


        int cmd = UdpSys::getOrder(datagram);
        int cmdIndex;
        int testCounts,testTimes;
        int cpuRate, memRate, cpuTemp, vdoTemp, hddTemp;
        QString outStr;
        QString testResult;
        switch(cmd){
        case CMD_STATUS:            //刷新下位机状态：回复
            outStr = UdpSys::getCmdOUtstr(datagram);
            if (outStr.length() == 0) {
                // error
            }else{
                UdpSys::getDevStatus(datagram, cpuRate, memRate, cpuTemp, vdoTemp, hddTemp);
                if (refreshUdpDevice(outStr, hostIPStr, cpuRate, memRate, cpuTemp, vdoTemp, hddTemp)) {
                    /* 新添加的设备，打印设备信息 */
                    appendLog(QString("getDevStatus from box_%1, ip:%2 <<\n%3")
                        .arg(devIndex).arg(hostIPStr).arg(outStr), LOG_DEBUG);
                }
            }
            break;
        case CMD_RUNCMD:
            outStr = UdpSys::getCmdOUtstr(datagram);
            if(devIndex != -1){
                if(udpDeviceList.at(devIndex).cmdOutStr.length() == 0){
                    appendLog(QString("cmd(%1) from box_%2, ip:%3 <<\n")
                              .arg(UdpSys::getCmdStr(datagram)).arg(devIndex).arg(hostIPStr), LOG_DEBUG);
                }
                QByteArray outarray = outStr.toLatin1();
                printf("%s\n", outarray.data());
                udpDeviceList[devIndex].cmdOutStr.append(outStr);
                if(outStr.length() > 20) {
                    udpDeviceList[devIndex].testLogs.append(outStr.left(10) + "..." + outStr.right(10));
                } else {
                    udpDeviceList[devIndex].testLogs.append(outStr);
                }

                if(!isStartTestCase){
                    if(devicesetup->devIndex == devIndex){
                        devicesetup->appendInfo(outStr);
                    }
                }
            }else{
                appendLog(QString("获取到错误的IP-'%1'反馈!!!").arg(hostIPStr), LOG_ERR);
            }
            break;
        case CMD_OUTCMD:
            if(devIndex != -1){
                appendLog(QString("cmd(%1) from box_%2, ip:%3-命令执行超时-'%4S'")
                          .arg(UdpSys::getCmdStr(datagram)).arg(devIndex).arg(hostIPStr).arg(UdpSys::getTimes(datagram)), LOG_WARN);
            }else{
                appendLog(QString("获取到错误的IP-'%1'反馈!!!").arg(hostIPStr), LOG_ERR);
            }
            break;
        case CMD_ENDCMD:
        case CMD_ERREND:
        case CMD_KILLALL:
            if(devIndex < 0){
                appendLog(QString("获取到错误的IP-'%1'反馈!!!").arg(hostIPStr), LOG_ERR);
                break;
            }
            if(udpDeviceList.at(devIndex).isReboot){                               // 正在执行重启命令，这里不进行结果分析
                return;
            }
            if(devIndex >= 0){
                if(!isStartTestCase){                           // 没有开始测试
                    outStr = UdpSys::getCmdOUtstr(datagram);
                    QByteArray outarray = outStr.toLatin1();
                    udpDeviceList[devIndex].testLogs.append(outStr);
                    if(devicesetup->devIndex == devIndex){
                        devicesetup->appendInfo(outStr);
                    }
                    return;
                }

                udpDeviceList[devIndex].isRuning = false;
                cmdIndex = udpDeviceList[devIndex].cmdIndex;
                if(udpDeviceList[devIndex].cmdResult.size() <= cmdIndex){          // 该条测试命令结果不存在
                    udpDeviceList[devIndex].cmdResult.append("");                  // 创建个空的结果
                }else{
                    udpDeviceList[devIndex].cmdResult[cmdIndex].append("\n");
                }
                if(cmd == CMD_ERREND){
                    testResult = udpDeviceList[devIndex].cmdOutStr;
                    udpDeviceList[devIndex].cmdResult[cmdIndex].append(testResult);
                    udpDeviceList[devIndex].cmdOutStr.clear();
                }else{
                    testResult = getResultFormOUT(udpDeviceList.at(devIndex).cmdOutStr, testCaseList.at(cmdIndex).resultStart,
                                                  testCaseList.at(cmdIndex).resultEnd, cmdIndex);
                    udpDeviceList[devIndex].cmdResult[cmdIndex].append(testResult);
                    udpDeviceList[devIndex].cmdOutStr.clear();
                }
                testCounts = udpDeviceList[devIndex].testCounts;
                udpDeviceList[devIndex].testCounts         += 1;
                udpDeviceList[devIndex].testTotalCounts    += 1;
                udpDeviceList[devIndex].testTotalUseTimes += testCaseList.at(cmdIndex).timeMax;
                if(udpDeviceList[devIndex].testCounts > testCaseList.at(cmdIndex).counts){      //当前测试次数达到要求
                    udpDeviceList[devIndex].cmdIndex = udpDeviceList[devIndex].cmdIndex+1;
                    testTimes = static_cast<int>(QDateTime::currentDateTime().toTime_t() - udpDeviceList.at(devIndex).startTestTime);
                    udpDeviceList[devIndex].cmdResult[cmdIndex] = resultHandle(udpDeviceList[devIndex].cmdResult[cmdIndex], cmdIndex);
                    udpDeviceList[devIndex].testTimes.append(testTimes);
                    udpDeviceList[devIndex].testCounts = 1;
                }
                appendLog(QString("cmd(%1) from box_%2, ip:%3-命令执行结束-'%4S'，第%5次测试结果：%6")
                          .arg(UdpSys::getCmdStr(datagram)).arg(devIndex).arg(hostIPStr)
                          .arg(UdpSys::getTimes(datagram)).arg(testCounts).arg(testResult), cmd == CMD_ERREND?LOG_ERR:LOG_INFO);
            }else{
                appendLog(QString("获取到错误的IP-'%1'反馈!!!").arg(hostIPStr), LOG_ERR);
            }
            break;
        default:
            appendLog(QString("[%1]检测到错误的帧头???, datalen: %2").arg(hostIPStr).arg(datagram.length()), LOG_WARN);
            break;
        }
    }

    // 处理剩余报文
    int length = UdpSys::getLeftStrLen(datagram);
    if(length <= 0){
        return;
    }

    QByteArray leftData = datagram.right(length);
    if(UdpSys::isCompletePack(leftData)){
        processRecvData(leftData, hostAddress);
    }else{
        if(devIndex >= 0){
            int type = (quint8)leftData.at(0);
            if(type >= CMD_STATUS && type <= CMD_KILLALL){
                appendLog(QString("[%1]检测到剩余包,有帧头,进行拼接,datalen: %2").arg(hostIPStr).arg(leftData.length()), LOG_WARN);
                udpDeviceList[devIndex].leftPack.append(leftData);
            }else{
                if(udpDeviceList.at(devIndex).leftPack.length() > 0){
                    appendLog(QString("[%1]检测到剩余包,无帧头,进行拼接,datalen: %2").arg(hostIPStr).arg(leftData.length()), LOG_WARN);
                    udpDeviceList[devIndex].leftPack.append(leftData);
                }else{
                    appendLog(QString("[%1]检测到剩余包,无帧头,无法进行拼接！！！,datalen: %2").arg(hostIPStr).arg(leftData.length()), LOG_ERR);

                    for(int i=0; i<leftData.length(); i++){
                        printf("%x ", leftData.at(i));
                    }
                    printf("\n");
                }
            }
            if(UdpSys::isCompletePack(udpDeviceList[devIndex].leftPack)){
                QByteArray newdatagram = udpDeviceList[devIndex].leftPack;
                udpDeviceList[devIndex].leftPack.clear();
                processRecvData(newdatagram, hostAddress);
            }
        }
    }
}

bool Systimer::refreshUdpDevice(QString macStr, QString ipAddress, int cpuRate, int memRate, int cpuTemp, int vdoTemp, int hddTemp)
{
    int realIndex;
    bool ret = false;

    int index = getIndexFromUList(udpDeviceList, macStr);
    if(-1 == index){                // 该设备是新增加的设备
        realIndex = udpDeviceList.length();
        if (realIndex > MAX_DEVICES) {
            appendLog(QString("err, dev count > %1").arg(realIndex), LOG_ERR);
            return false;
        }
        UdpDevice uDevice;
        if(macStr.length() == 17*8){
            macStr = macStr.right(17*4) + macStr.left(17*4);
        }
        uDevice.macStr = macStr;
        //uDevice.mac1 = macStr.left(17);
        uDevice.mac2 = macStr.left(17);
        uDevice.mac1 = macStr.right(17);
        uDevice.isRuning = false;
        uDevice.status   = STAT_NORMAL;
        uDevice.cmdIndex = 0;
        udpDeviceList.append(uDevice);
        udpDeviceList[realIndex].testCounts  = 1;            // 新增的设备，由于未进行过测试，这里配置默认从第一次开始测试
        udpDeviceList[realIndex].isTestEnded = false;
        udpDeviceList[realIndex].testTotalUseTimes = 0;
        udpDeviceList[realIndex].testTotalCounts = 0;

        emit testDevTrigger(realIndex, true, 0, 0, STAT_NORMAL);
        emit testDevStatTrigger(realIndex, LOG_DEBUG, "connect success");
        ret = true;
    }else{
        realIndex = index;
    }

    if(macStr.length() < udpDeviceList[realIndex].macStr.length()){
        udpDeviceList[realIndex].status = STAT_ERR_CMD;
        emit testDevStatTrigger(realIndex, LOG_ERR, "设备网卡丢失");
    }

    /* 更新mac地址，与上次在线时间 */
    unsigned long nowTime = QDateTime::currentDateTime().toTime_t();
    if(udpDeviceList[realIndex].status == STAT_RESTARTED){
        if(nowTime - udpDeviceList[realIndex].lastOnlineTime > 30){
            udpDeviceList[realIndex].status = STAT_NORMAL;
            emit testDevStatTrigger(realIndex, LOG_INFO, "正常测试中...");
        }
    }

    udpDeviceList[realIndex].ipAddress = ipAddress;
    udpDeviceList[realIndex].lastOnlineTime = nowTime;
    udpDeviceList[realIndex].cpuRate    = cpuRate;
    udpDeviceList[realIndex].memRate    = memRate;
    udpDeviceList[realIndex].cpuTemp    = cpuTemp;

    if(udpDeviceList[realIndex].status == STAT_OFFLINE){
        udpDeviceList[realIndex].status = STAT_NORMAL;
        emit testDevStatTrigger(realIndex, LOG_DEBUG, "connect success");
    }
    emit    statusTrigger(realIndex, udpDeviceList[realIndex].mac1, udpDeviceList[realIndex].ipAddress,
                          cpuRate, memRate, cpuTemp, vdoTemp, hddTemp);

    return ret;
}

/* 发送广播，获取下位机节点信息 */
void Systimer::refreshDevStatus()
{
    static int counts = 0;
    QString broadAddress = this->localBroadcast;
    if(broadAddress.length() > 0){
        //appendLog(QString("send broadcast: %1_%2_%3").arg(broadAddress).arg(PORT_COMM_1).arg(PORT_COMM_2), LOG_DEBUG);
        UdpSys::sendDataGram_toAddress(udpSocket_1, PORT_UDP_COMM_1, broadAddress,
                                       CMD_STATUS, 0, "", "");
        UdpSys::sendDataGram_toAddress(udpSocket_1, PORT_UDP_COMM_1, "255.255.255.255",
                                       CMD_STATUS, 0, "", "");

        //bool needRefresh = false;
        for(int i=0; i<udpDeviceList.length(); i++){
            /* 设备在线状态判断 */
            unsigned long now_times = QDateTime::currentDateTime().toTime_t();
            if(now_times - udpDeviceList.at(i).lastOnlineTime > 30){
                if(udpDeviceList.at(i).cmdIndex < 0){
                    // 节点尚未开始测试，直接移除该节点???
                    //udpDeviceList.removeAt(i);
                    //i--;
                    continue;
                }else if(udpDeviceList.at(i).cmdIndex >= testCaseList.length()){
                    if(udpDeviceList.at(i).isTestEnded){
                        udpDeviceList[i].status = STAT_OFFLINE;
                        emit testDevStatTrigger(i, LOG_WARN, "测试完成，设备关机");
                    }else{
                        udpDeviceList[i].status = STAT_OFFLINE;
                        emit testDevStatTrigger(i, LOG_ERR, "设备掉线");
                    }
                }else if(udpDeviceList[i].status == STAT_RESTARTED){                // 设备重新开始测试
                    if(now_times - udpDeviceList.at(i).lastOnlineTime > 120){
                        udpDeviceList[i].status = STAT_ERR_CMD;
                        emit testDevStatTrigger(i, LOG_ERR, "系统未知故障");
                    }
                }else if(udpDeviceList.at(i).isRebooted  && now_times - udpDeviceList.at(i).lastOnlineTime > 120){
                    // 节点执行了重启命令，但没有开机成功
                    udpDeviceList[i].status = STAT_ERR_RESET_POWERON;
                    emit testDevStatTrigger(i, LOG_ERR, "系统开机失败 ");
                }else if((!udpDeviceList.at(i).isRebooted) && udpDeviceList.at(i).isReboot  && now_times - udpDeviceList.at(i).lastOnlineTime > 60){
                    // 节点执行了重启命令，但没有成功关机
                    udpDeviceList[i].status = STAT_ERR_RESET_POWEROFF;
                    emit testDevStatTrigger(i, LOG_ERR, "系统关机失败 ");
                }else if((!udpDeviceList.at(i).isReboot) && (!udpDeviceList.at(i).isRebooted)){
                    // 节点在进行其它测试项，机器无响应（出现硬件故障）
                    if(isStartTestCase){
                        udpDeviceList[i].status = STAT_ERR_CMD;
                        emit testDevStatTrigger(i, LOG_ERR, "系统未知故障");
                    }else{
                        udpDeviceList[i].status = STAT_OFFLINE;
                        emit testDevStatTrigger(i, LOG_ERR, "设备掉线");
                    }
                }
            }
            /* 设备测试进度刷新 */
            if(isStartTestCase && udpDeviceList.at(i).isRuning){
                if(udpDeviceList.at(i).cmdIndex >= 0 && udpDeviceList.at(i).cmdIndex < testCaseList.length()){
                    unsigned long usedTimes = now_times - udpDeviceList.at(i).startCmdTime;
                    int currentIndex = udpDeviceList.at(i).cmdIndex;
                    if (currentIndex >= testCaseList.length()) {
                        currentIndex = testCaseList.length() - 1;
                    }
                    int currentProcess = usedTimes * 1000.0 / testCaseList.at(currentIndex).timeMax;

                    if(usedTimes > testCaseList.at(currentIndex).timeMax){
                        usedTimes = testCaseList.at(currentIndex).timeMax;
                    }

                    //qDebug() << "usedTimes: " << usedTimes << "--totalC: " << udpDeviceList.at(i).testTotalCounts << "--stotal: " << setupcase.totalTestCounts;
                    int totalProcess = 1000*(usedTimes*1.0/testCaseList.at(currentIndex).timeMax+udpDeviceList.at(i).testTotalCounts)/setupcase.totalTestCounts;
                    if(totalProcess > 1000)
                        totalProcess = 1000;
                    //qDebug() << "cur: " << currentProcess << "---total: " << totalProcess;
                    emit testProcessTrigger(i, now_times - udpDeviceList.at(i).startCmdTime, currentProcess, totalProcess);
                }
            }else if(udpDeviceList.at(i).cmdIndex >= testCaseList.length()){
                emit testProcessTrigger(i, now_times - udpDeviceList.at(i).startCmdTime, 1000, 1000);     //测试完成，刷新进度条至100%
            }
        }
    }else{
        counts++;
        //if(counts % 3 == 0)
        //    SingleTonSToast::toast("错误：本地网络未连通，请检查网线是否连接！");
    }
}

